package com.example.usermanagement.handle;


import com.example.usermanagement.enums.ResponseStatus;
import com.example.usermanagement.exception.ServerErrorException;
import com.example.usermanagement.vo.ResultVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.util.List;


/**
 * @author yha
 * @ClassName
 * @description:请求统一返回处理
 * @date 2024年09月10日
 * @version: 1.0.0
 */
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler implements  ResponseBodyAdvice {

    /**
     * 进行控制器异常自定义处理
     * @param exception
     * @return
     */
    @ExceptionHandler(value = {Exception.class,RuntimeException.class})
    @ResponseBody
    private ResultVO defaultErrorHandler(Exception exception) {
        ResultVO coreResult = new ResultVO();
        coreResult.setCode(ResponseStatus.ERROR.getCode());
        if (exception instanceof MethodArgumentNotValidException) {
            StringBuilder message = new StringBuilder(exception.getMessage());
            MethodArgumentNotValidException methodArgumentNotValidException = MethodArgumentNotValidException.class.cast(exception);
            List<ObjectError> objectErrors = methodArgumentNotValidException.getBindingResult().getAllErrors();
            if (!objectErrors.isEmpty()) {
                message = new StringBuilder();
                for (ObjectError objectError : objectErrors) {
                    message.append(objectError.getDefaultMessage()).append(",");
                }
            }
            log.error(message.toString());
            coreResult.setMsg(message.toString());

        }else if (exception instanceof ServerErrorException) {
            log.error(exception.getMessage(), exception);
            coreResult.setException(exception);
        } else if (exception instanceof BindException) {
            StringBuilder message = new StringBuilder(exception.getMessage());
            BindException bindException=BindException.class.cast(exception);
            BindingResult bindingResult = bindException.getBindingResult();
            if(bindingResult.hasErrors()){
                StringBuilder errMess=new StringBuilder();
                bindingResult.getAllErrors().stream().forEach(error->{
                    if (errMess.length()>0){
                        errMess.append(",");
                    }
                    Object[] arguments = error.getArguments();
                    if (arguments.length>0){
                        DefaultMessageSourceResolvable argument = (DefaultMessageSourceResolvable) arguments[0];
                        errMess.append(argument.getDefaultMessage()+":"+error.getDefaultMessage());
                    }
                });
                message=errMess;
            }
            log.error(message.toString(),exception);
            coreResult.setMsg(message.toString());
        } else {
            log.error("异常:{}",exception.getMessage(),exception);
            coreResult.setMsg(exception.getMessage());
        }
        return coreResult;
    }

    @Override
    public boolean supports(MethodParameter methodParameter, Class aClass) {


        return true;
    }

    /**
     * 控制器返回对象进行统一封装处理
     * @param body
     * @param methodParameter
     * @param mediaType
     * @param aClass
     * @param serverHttpRequest
     * @param serverHttpResponse
     * @return
     */
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class aClass,
                                  ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        String clazz = methodParameter.getParameterType().getName();
        ResultVO coreResult = null;


        if (clazz.contains("String")) {
            coreResult = new ResultVO();
            coreResult.setData(body);
        } else if (clazz.contains("ResultVO")) {
            coreResult = ResultVO.class.cast(body);
        } else {
            coreResult = new ResultVO(body);
        }
        return coreResult;
    }
}
